package edu.whu.rose.clock.kps.spindex;

import java.io.File;
import java.util.Date;

import com.sleepycat.bind.tuple.IntegerBinding;
import com.sleepycat.je.Cursor;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;

import edu.whu.rose.clock.setup.IndexEnvironment;
import edu.whu.rose.clock.ssql.binding.SubGraphBinding;
import edu.whu.rose.clock.ssql.graph.RRadiusSubGraph;
import edu.whu.rose.clock.ssql.graph.SubGraphDB;

public class ShortestPathIndexManager {

	private ShortestPathIndexDB disDB;
	private ShortestPathIndexDB preDB;
	
	public ShortestPathIndexManager(Environment dbEnv) {
		disDB = new ShortestPathIndexDB(dbEnv, "distances");
		preDB = new ShortestPathIndexDB(dbEnv, "predecessors");
	}
	
	public ShortestPathIndexManager(Environment dbEnv, String dbName1, String dbName2) {
		disDB = new ShortestPathIndexDB(dbEnv, dbName1);
		preDB = new ShortestPathIndexDB(dbEnv, dbName2);
	}
	
	public static void main(String[] args) {
//		File file = new File("dbEnv_shortestpath");
//		if (file.isDirectory()) {
//			File[] files = file.listFiles();
//			for (int i = 0; i < files.length; i++) {
//				files[i].delete();
//			}
//		}
		
		IndexEnvironment ie = new IndexEnvironment("dbEnv_shortestpath");
		if (!ie.openEnv()) {
			System.exit(1);
		}
		
		ShortestPathIndexManager spim = new ShortestPathIndexManager(ie.getEnvironment());
		spim.init();
		
		SubGraphDB sgdb = new SubGraphDB("dbEnv_subgraph");
		if (!sgdb.initEnv() || !sgdb.openDB()) {
			return;
		}
		
		spim.buildIndex(sgdb);
		
		spim.close();
		ie.closeEnv();
	}
	
	public void init() {
		if (!disDB.openDB() || !preDB.openDB()) {
			System.exit(1);
		}
	}
	
	public void close() {
		disDB.closeDB();
		preDB.closeDB();
	}
	
	public void buildIndex(SubGraphDB sgdb) {
		if (sgdb == null) {
			return;
		}
		
		Cursor cursor = null;
		DatabaseEntry key = new DatabaseEntry();
		DatabaseEntry value = new DatabaseEntry();
		
		try {
			cursor = sgdb.getCursorOfSubgraphs();
			Date start = new Date();
			while (cursor.getNext(key, value, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
				IntegerBinding ib = new IntegerBinding();
				int subgraph_id = ib.entryToInt(key);
				if (subgraph_id > 92000 && subgraph_id <= 120000) {
					SubGraphBinding sgb = new SubGraphBinding();
					RRadiusSubGraph rrsg = (RRadiusSubGraph) sgb.entryToObject(value);

					if (rrsg == null) {
						System.err.println(subgraph_id);
					}
					
					ShortestPathInSubgraph spis = ShortestPathSearch.run(rrsg);
					
					insertIntoIndex(subgraph_id, rrsg.getVertexes(), spis);
					
//					if (subgraph_id > 10) {
//						break;
//					}
					
					if (subgraph_id % 1000 == 0) {
						Date end = new Date();
						System.out.print("processed " + subgraph_id);
						System.out.println(" : " + (end.getTime() - start.getTime()) + "ms");
						start = end;
						System.gc();
					}
				}
			}
		}
		catch (DatabaseException ex) {
			ex.printStackTrace();
		}
		finally {
			try {
				if (cursor != null) {
					cursor.close();
				}
				sgdb.closeDB();
			}
			catch (DatabaseException ex) {
				ex.printStackTrace();
				System.err.println("Error: closing cursor");
			}
		}
	}
	
	private void insertIntoIndex(int subgraph, int[] vertexes, ShortestPathInSubgraph spis) throws DatabaseException {
		for (int i = 0; i < vertexes.length; i++) {
			int vertex = vertexes[i];
			int[] distances = spis.getDistances(i);
			int[] predecessors = spis.getPredecessors(i);
//			ShortestPathIndexItem spii = new ShortestPathIndexItem(distances, predecessors);
			disDB.put(subgraph, vertex, distances);
			preDB.put(subgraph, vertex, predecessors);
		}
	}

}
